/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __IShaderEffect_H__
#define __IShaderEffect_H__

#pragma once

#include <map>
#include <vector>

#include "ITexture.h"
#include "IResource.h"
#include "geom/Matrix.h"
#include "IRenderer.h"

enum eEffectDataType {
	TYPE_TEXTURE, 
	TYPE_FLOAT, 
	TYPE_INT,
	TYPE_BOOL,
	TYPE_MATRIX
};

struct sEffectData {
	eEffectDataType dataType;
	unsigned int numElements;
	void* data;
};

/// A handle to a shader parameter
typedef unsigned int SHADERHANDLE;

/**
 * \ingroup CoreEngine
 *
 * The IShaderEffect interface.<br>
 * This represents a container format (i.e. .fx Files) for shader.<br>
 * Inside a shader effect, several techniques can be specified, each using multiple rendering passes.<br>
 * An IShaderEffect instance can be created using ResourceFactory::loadShaderEffect(). Use getParameterByName to obtain
 * a SHADERHANDLE from the effect file. This can later be used as reference.
 *
 * \date 03-28-2007
 *
 * \author juckel
 *
 * \todo Remove all the add.. functions
 * \todo Change the set.. functions to SHADERHANDLE functions
 *
 */
class DLL_EXPORT IShaderEffect 
	: public IResource
{
public:
	virtual ~IShaderEffect(void);

	/// Load an effect from a .fx file. Do not call directly. Use EffectFactory::load() instead
	virtual bool load(const std::string &filename) = 0;

	/// Bind an effect to be used inside the program
	virtual bool bind(bool useBestValidTechnique = true) = 0;

	/// Bind a shader as a global shader. Local Transformations are always passed to the global shader as Semantic WORLDGLOBAL
	virtual bool bindGlobal();

	static IShaderEffect *GetGlobal();

	/// Release the effect, so it is no longer used
	virtual bool unbind() = 0;

	/// Begin rendering of an effect pass
	virtual bool beginPass(int pass = 0) = 0;

	/// End rendering of an effect pass
	virtual bool endPass() = 0;

	/// Return the number of passes. Default is 1
	virtual int getNumPasses();

	/// Set the texture variables to be used inside the effect. 
	/// Textures are added with addTexture
	virtual bool setVariables() = 0;

	/// Specifies the current technique to use.
	virtual bool setTechnique(const std::string &technique) = 0;
	virtual bool setTechnique(const SHADERHANDLE &handle) = 0;

	/// Set an integer array for use inside the effect
	virtual bool setInt(const SHADERHANDLE &handle, int* ints, int size) = 0;
	
	/// Set an float array for use inside the effect
	virtual bool setFloat(SHADERHANDLE &handle, float* floats, int size) = 0;
	
	/// Set an boolean array for use inside the effect
	virtual bool setBoolean(const SHADERHANDLE &handle, const bool* bools, int size) = 0;

	/// Set an math::Matrix4 for use inside the effect
	virtual bool setMatrix(const SHADERHANDLE &handle, math::Matrix4 *matrix) = 0;

	virtual bool setGlobalWorldTransformMatrix(math::Matrix4 *matrix) = 0;

	/// Set the texture directly without adding it the the list
	virtual bool setTexture(const SHADERHANDLE &handle, ITexture *tex) = 0;

	/// Set an ambiguious chunk of data in the shader
	virtual bool setData(const SHADERHANDLE &handle, void* data, int numBytes) = 0;

	/// Add a texture reference to the effect. This will be assigned by calling setVariables()
	virtual bool addTexture(const SHADERHANDLE &handle, ITexture* texture) = 0;

	/// Indicate if a certain parameter exists
	virtual bool hasParameter(const std::string &identifier) = 0;
	
	/// Get a parameter from the effect. It return the value of the parameter "identifier" and also the handle vie the outHandle
	virtual int* getParameterValueAsIntArray(const std::string &identifier, int count = 1) = 0;
	
	/// Get a parameter from the effect. It return the value of the parameter "identifier" and also the handle vie the outHandle
	virtual float* getParameterValueAsFloatArray(const std::string &identifier, int count = 1) = 0;

	/// Get the SHADERHANDLE for a specified parameter or technique
	virtual SHADERHANDLE getParameterByName(const std::string &identifier) = 0;

	/// Get the SHADERHANDLE for a specified semantic
	virtual SHADERHANDLE getParameterBySemantic(const std::string &semantic) = 0;

	/// Starts a parameter block
	virtual bool beginParameterBlock() = 0;
	/// Ends a parameter block and returns the handle to it
	virtual SHADERHANDLE endParameterBlock() = 0;
	/// Applies a parameter block to the shader
	virtual void applyParameterBlock(SHADERHANDLE blockHandle) = 0;

	/// Registers a data segment for the shader. All shader that are loaded after this chunk is registered try to get the identifier and assign the value to it.
	static void RegisterHandle(const std::string &identifier, eEffectDataType dataType, unsigned int numElements, void* data);

	/// Indicates if the effect is loaded
	bool isLoaded() const;

	virtual unsigned int getType() { return RESTYPE_SHADEREFFECT; };

protected:
	void checkRegisteredHandles();
	/// Default constructor is protected
	IShaderEffect(void);

	static IShaderEffect *s_pGlobalShader;
	

	bool                  bIsLoaded;
	unsigned int          uiNumPasses;
	IRenderer            *pRenderer;
	
	typedef std::map<std::string, sEffectData> registereddata_list;
	static std::map<std::string, sEffectData> m_lRegisteredData;
};

#endif
